# -*- encoding: utf-8 -*-
import base64
from enum import Enum
from typing import Optional, Any, List

import requests

from bct.tools.common.bct_util import get_logger
from bct.tools.http.trade.bct4_trade_dto import TradeDTO, FindTrades

logger = get_logger("bct4client")

user_agent = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.99 Safari/537.36 Edg/97.0.1072.69 '


class JsonConvException(Exception):
    pass


class CallErrorException(Exception):
    pass


class BCTVer(Enum):
    V_4X = "4X"
    V_42 = "42"


def _get_token(auth_username: str, auth_password: str, server_url: str, base64_encode: bool = True) -> str:
    auth_url = "%s%s" % (server_url, '/api/auth-service/users/login')

    if base64_encode:
        usr_name = base64.b64encode(auth_username.encode())
        usr_pwd = base64.b64encode(auth_password.encode())
    else:
        usr_name = auth_username
        usr_pwd = auth_password

    auth_body = {
        'userName': usr_name.decode(),
        'password': usr_pwd.decode()
    }
    headers = {'User-Agent': user_agent}
    auth = requests.post(auth_url, json=auth_body, headers=headers)
    try:
        _token = auth.json()['token']
        return _token
    except Exception:
        error_message = auth.json()['errorMessage']
        raise ValueError(error_message)


def rpc_call(method: str, params: dict, server_url: str, service: Optional[str] = None, token: Optional[str] = None):
    if service is None:
        url = "%s%s" % (server_url, '/api/rpc',)
    else:
        url = "%s/%s%s" % (server_url, service, '/api/rpc',)
    headers = {
        'Authorization': "Bearer %s" % token,
        'User-Agent': user_agent
    }
    body = {'method': method, 'params': params}
    r = requests.post(url, json=body, headers=headers).json()
    if 'error' in r:
        raise JsonConvException(f'failed convertor call {method}')
    return r


def call_post(param: Any, server_url: str, path: Optional[str] = None, token: Optional[str] = None) -> Any:
    url = "%s/%s" % (server_url, path)
    headers = {
        'Authorization': 'Bearer ' + token,
        'User-Agent': user_agent
    }
    body = param
    r = requests.post(url, json=body, headers=headers)
    if r.status_code == 200:
        if len(r.content) > 0:
            r = r.json()
            if isinstance(r, bool) or isinstance(r, int):
                return r
            if 'error' in r:
                raise JsonConvException(f'failed convertor call {path}')
            elif 'errorMessage' in r:
                raise CallErrorException(r['errorMessage'])
            return r
        else:
            return {}
    else:
        return r


def call_get(params: dict, server_url: str, path: Optional[str] = None, token: Optional[str] = None):
    url = "%s/%s" % (server_url, path)
    headers = {
        'User-Agent': user_agent,
        'Authorization': 'Bearer ' + token
    }
    r = requests.get(url, headers=headers).json()
    if isinstance(r, bool):
        return r

    if 'error' in r:
        raise JsonConvException(f'failed convertor call {path}')
    else:
        print(r)
    return r


class BCT4Client:
    server_url: str
    script_name: str
    script_password: str
    token: Optional[str] = None
    bct_ver: BCTVer

    def __login(self):
        if self.token is None:
            self.token = _get_token(self.script_name, self.script_password, self.server_url)
            logger.info(
                "login:%s  username:%s bct version:%s" % (self.server_url, self.script_name, self.bct_ver.value))

    def __get_url(self) -> str:
        """
        按照版本号构建url
        :return:
        """
        if self.bct_ver == BCTVer.V_42:
            return "%s%s" % (self.server_url, '/bct')
        else:
            return self.server_url

    def call_post_raw(self, params: dict, path: Optional[str] = None) -> Any:
        """
        发送post请求
        :param params:
        :param path:
        :return:
        """
        self.__login()
        return call_post(params, self.__get_url(), path, self.token)

    def find_trades(self, query) -> List:
        """
        读取交易
        :param query:
        :return:
        """
        json = call_post(
            query,
            self.__get_url(),
            'trade-service/findTrades',
            self.token
        )
        result = []
        if isinstance(json, List):
            for i in json:
                result.append(i)
        return result

    def find_pricing_trades(self, query) -> List:
        """
        读取交易
        :param query:
        :return:
        """
        json = call_post(
            query,
            self.__get_url(),
            'trade-service/findPricingTrades',
            self.token
        )
        result = []
        if isinstance(json, List):
            for i in json:
                result.append(i)
        return result

    def fetch_dict(self, group_names: List[str], page: int = 0, page_size: int = 20) -> dict:
        """
        拉码表
        :return:
        """
        self.__login()
        return call_post({"page": page, "pageSize": page_size, "groupNames": group_names},
                         self.__get_url(),
                         'reference-data-service/dictionary/page-dict',
                         self.token)

    def find_dict_detail_by_id(self, dict_id: str) -> dict:
        """
        读取码表
        :return:
        """
        self.__login()
        return call_post({"id": dict_id},
                         self.__get_url(),
                         'reference-data-service/dictionary/find-dict-detail-by-id',
                         self.token)

    def fetch_trade_of_today_open(self, page_num: int, page_size: int) -> Any:
        """
        获取当日开仓交易
        :param page_num:
        :param page_size:
        :return:
        """
        return call_post(
            {
                "page": page_num,
                "pageSize": page_size,
                "customFilter": 'OPEN_TODAY'
            },
            self.__get_url(),
            'trade-service/findTradesPaged',
            self.token)

    def fetch_dict_by_key(self, dict_key: str):
        """
        根据字典key获取字典信息
        :param dict_key:
        :return:
        """
        return call_post(
            {
                "dictKey": dict_key
            },
            self.__get_url(),
            'reference-data-service/dictionary/enum/findByDictKey',
            self.token)

    def find_events_by_trade_id(self, trade_id):
        return call_post(
            {
                "tradeId": trade_id
            },
            self.__get_url(),
            'trade-service/findEventsByTradeId',
            self.token)

    def find_operation_log(self, params):
        return call_post(
            params,
            self.__get_url(),
            'auth-service/findOperationLogsPaged',
            self.token)

    def find_user_list(self):
        return call_post(
            {},
            self.__get_url(),
            'auth-service/authUser/authUserList',
            self.token)

    def __init__(self, server_url: str, script_name: str, script_password: str, bct_ver: BCTVer = BCTVer.V_42):
        """
        初始化客户端
        :param server_url: 服务器地址 http|https://xxxx.xxx.xxx
        :param script_name:  脚本用户名
        :param script_password: 脚本用户密码
        :param bct_ver: 如果是4.1及以下版本，请选择V_4X
        """
        self.bct_ver = bct_ver
        self.server_url = server_url
        self.script_name = script_name
        self.script_password = script_password
        self.__login()
